using System;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;

using Crainiate.Data.Persistence.Tools.Properties;

namespace Crainiate.Data.Persistence.Tools
{
    public partial class SelectAssemblyForm : WizardBaseForm
    {
        private Assembly _assembly;
        private Assembly[] _references;

        public SelectAssemblyForm()
        {
            InitializeComponent();

            cmdPrevious.Enabled = false;
            
            //Load the previous paths settings
            string setting = Settings.Default.AssemblyPaths;

            if (setting != null && setting.Length > 0)
            {
                string[] paths = setting.Split("|".ToCharArray());
                foreach (string path in paths)
                {
                    if (path.Length > 0) cboPath.Items.Add(path);
                }

                cboPath.Text = paths[0];
            }
        }

        public Assembly Assembly
        {
            get
            {
                return _assembly;
            }
        }

        public Assembly[] References
        {
            get
            {
                return _references;
            }
        }

        protected override void OnNextClick(object sender, EventArgs e)
        {
            if (cboPath.Text.Trim().Length == 0)
            {
                MessageBox.Show("Select a path to an assembly file.", "Invalid Assembly Path", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            try
            {
                //Have to load full to check IPersistable
                _assembly = Assembly.LoadFile(cboPath.Text);
            }
            catch
            {
                MessageBox.Show("The path specified could not be loaded as an assembly.", "Invalid Assembly", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //Load all referenced assemblies
            LoadReferencedAssemblies(_assembly);

            //Save the selected value and any previous values as a delimited string
            string setting = Settings.Default.AssemblyPaths;
            string newSetting = cboPath.Text;

            if (setting.Length > 0)
            {
                string[] paths = setting.Split("|".ToCharArray());
                foreach (string path in paths)
                {
                    if (path != cboPath.Text) newSetting += "|" + path;
                }
            }

            Settings.Default.AssemblyPaths = newSetting;
            Settings.Default.Save();

            base.OnNextClick(sender, e);
        }

        private void btnLookup_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog(this);

            if (result == DialogResult.OK)
            {
                cboPath.Text = openFileDialog1.FileName;
            }
        }

        private void LoadReferencedAssemblies(Assembly assembly)
        {
            List<Assembly> references = new List<Assembly>();

            FileInfo fileInfo = new FileInfo(assembly.Location);

            foreach (AssemblyName name in assembly.GetReferencedAssemblies())
            {
                Assembly reference = null;

                //Assembly reference has to be in same folder or in GAC
                reference = LoadAssembly(name, fileInfo.DirectoryName);

                if (reference == null)
                {
                    throw new Exception("Unable to load referenced Assembly " + name.FullName);
                }
                
                references.Add(reference);
            }

            _references = references.ToArray();

        }

        private Assembly LoadAssembly(AssemblyName name, string path)
        {
            Assembly reference = null;

            //Try load from GAC
            try
            {
                //Have to load full to check IPersistable
                reference = Assembly.Load(name.FullName);
            }
            catch
            {

            }

            //Try load from file
            if (reference == null)
            {
                path = path + @"\" + name.Name + ".dll";

                try
                {
                    //Have to load full to check IPersistable
                    reference = Assembly.LoadFile(path);
                }
                catch
                {

                }
            }

            return reference;
        }
    }
}